package cn.edu.sgu.www.mhxysy.function.computer.score.impl;

import cn.edu.sgu.www.mhxysy.base.GroupResult;
import cn.edu.sgu.www.mhxysy.entity.baoshi.Baoshi;
import cn.edu.sgu.www.mhxysy.entity.baoshi.EquipmentBaoshi;
import cn.edu.sgu.www.mhxysy.entity.change.RoleChangeSorcery;
import cn.edu.sgu.www.mhxysy.entity.equipment.Equipment;
import cn.edu.sgu.www.mhxysy.entity.fabao.Fabao;
import cn.edu.sgu.www.mhxysy.entity.fabao.FabaoCategory;
import cn.edu.sgu.www.mhxysy.entity.fabao.FabaoLiangyiAttribute;
import cn.edu.sgu.www.mhxysy.entity.fabao.FabaoLiangyiAttributeValue;
import cn.edu.sgu.www.mhxysy.entity.gang.GangSkill;
import cn.edu.sgu.www.mhxysy.entity.jingmai.JingmaiPoint;
import cn.edu.sgu.www.mhxysy.entity.jingmai.StarStone;
import cn.edu.sgu.www.mhxysy.entity.jingmai.StarStoneCategory;
import cn.edu.sgu.www.mhxysy.entity.potency.PotencyFruit;
import cn.edu.sgu.www.mhxysy.entity.qiling.Qiling;
import cn.edu.sgu.www.mhxysy.entity.role.RoleAccount;
import cn.edu.sgu.www.mhxysy.entity.school.SchoolSkill;
import cn.edu.sgu.www.mhxysy.entity.xingyin.Xingyin;
import cn.edu.sgu.www.mhxysy.entity.xiulian.RoleXiulian;
import cn.edu.sgu.www.mhxysy.entity.zhenfa.RoleZhenfa;
import cn.edu.sgu.www.mhxysy.enums.FabaoTypes;
import cn.edu.sgu.www.mhxysy.enums.InlayStatus;
import cn.edu.sgu.www.mhxysy.enums.WearStatus;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.function.computer.score.ScoreComputer;
import cn.edu.sgu.www.mhxysy.mapper.baoshi.BaoshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.baoshi.EquipmentBaoshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.change.RoleChangeSorceryMapper;
import cn.edu.sgu.www.mhxysy.mapper.equipment.EquipmentMapper;
import cn.edu.sgu.www.mhxysy.mapper.fabao.FabaoCategoryMapper;
import cn.edu.sgu.www.mhxysy.mapper.fabao.FabaoLiangyiAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.fabao.FabaoLiangyiAttributeValueMapper;
import cn.edu.sgu.www.mhxysy.mapper.fabao.FabaoMapper;
import cn.edu.sgu.www.mhxysy.mapper.gang.GangSkillMapper;
import cn.edu.sgu.www.mhxysy.mapper.jingmai.JingmaiPointMapper;
import cn.edu.sgu.www.mhxysy.mapper.jingmai.StarStoneCategoryMapper;
import cn.edu.sgu.www.mhxysy.mapper.jingmai.StarStoneMapper;
import cn.edu.sgu.www.mhxysy.mapper.potency.PotencyFruitMapper;
import cn.edu.sgu.www.mhxysy.mapper.potency.PotencyFruitPatternMapper;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingMapper;
import cn.edu.sgu.www.mhxysy.mapper.role.RoleAccountMapper;
import cn.edu.sgu.www.mhxysy.mapper.school.SchoolSkillMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinMapper;
import cn.edu.sgu.www.mhxysy.mapper.xiulian.RoleXiulianMapper;
import cn.edu.sgu.www.mhxysy.mapper.zhenfa.RoleZhenfaMapper;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.util.CollectionUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 角色评分计算器
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Component
public class RoleScoreComputer implements ScoreComputer {

    private final FabaoMapper fabaoMapper;
    private final BaoshiMapper baoshiMapper;
    private final QilingMapper qilingMapper;
    private final XingyinMapper xingyinMapper;
    private final EquipmentMapper equipmentMapper;
    private final GangSkillMapper gangSkillMapper;
    private final StarStoneMapper starStoneMapper;
    private final RoleZhenfaMapper roleZhenfaMapper;
    private final RoleAccountMapper roleAccountMapper;
    private final SchoolSkillMapper schoolSkillMapper;
    private final RoleXiulianMapper roleXiulianMapper;
    private final JingmaiPointMapper jingmaiPointMapper;
    private final PotencyFruitMapper potencyFruitMapper;
    private final FabaoCategoryMapper fabaoCategoryMapper;
    private final EquipmentBaoshiMapper equipmentBaoshiMapper;
    private final RoleChangeSorceryMapper roleChangeSorceryMapper;
    private final StarStoneCategoryMapper starStoneCategoryMapper;
    private final PotencyFruitPatternMapper potencyFruitPatternMapper;
    private final FabaoLiangyiAttributeMapper fabaoLiangyiAttributeMapper;
    private final FabaoLiangyiAttributeValueMapper fabaoLiangyiAttributeValueMapper;

    @Autowired
    public RoleScoreComputer(
            FabaoMapper fabaoMapper,
            BaoshiMapper baoshiMapper,
            QilingMapper qilingMapper,
            XingyinMapper xingyinMapper,
            EquipmentMapper equipmentMapper,
            GangSkillMapper gangSkillMapper,
            StarStoneMapper starStoneMapper,
            RoleZhenfaMapper roleZhenfaMapper,
            RoleAccountMapper roleAccountMapper,
            SchoolSkillMapper schoolSkillMapper,
            RoleXiulianMapper roleXiulianMapper,
            JingmaiPointMapper jingmaiPointMapper,
            PotencyFruitMapper potencyFruitMapper,
            FabaoCategoryMapper fabaoCategoryMapper,
            EquipmentBaoshiMapper equipmentBaoshiMapper,
            RoleChangeSorceryMapper roleChangeSorceryMapper,
            StarStoneCategoryMapper starStoneCategoryMapper,
            PotencyFruitPatternMapper potencyFruitPatternMapper,
            FabaoLiangyiAttributeMapper fabaoLiangyiAttributeMapper,
            FabaoLiangyiAttributeValueMapper fabaoLiangyiAttributeValueMapper) {
        this.fabaoMapper = fabaoMapper;
        this.baoshiMapper = baoshiMapper;
        this.qilingMapper = qilingMapper;
        this.xingyinMapper = xingyinMapper;
        this.equipmentMapper = equipmentMapper;
        this.gangSkillMapper = gangSkillMapper;
        this.starStoneMapper = starStoneMapper;
        this.roleZhenfaMapper = roleZhenfaMapper;
        this.roleAccountMapper = roleAccountMapper;
        this.schoolSkillMapper = schoolSkillMapper;
        this.roleXiulianMapper = roleXiulianMapper;
        this.jingmaiPointMapper = jingmaiPointMapper;
        this.potencyFruitMapper = potencyFruitMapper;
        this.fabaoCategoryMapper = fabaoCategoryMapper;
        this.equipmentBaoshiMapper = equipmentBaoshiMapper;
        this.roleChangeSorceryMapper = roleChangeSorceryMapper;
        this.starStoneCategoryMapper = starStoneCategoryMapper;
        this.potencyFruitPatternMapper = potencyFruitPatternMapper;
        this.fabaoLiangyiAttributeMapper = fabaoLiangyiAttributeMapper;
        this.fabaoLiangyiAttributeValueMapper = fabaoLiangyiAttributeValueMapper;
    }

    /**
     * 计算角色总评分
     * @param roleId 角色ID
     * @return Integer 角色评分
     */
    @Override
    public Integer apply(String roleId) {
        RoleAccount roleAccount = roleAccountMapper.selectById(roleId);

        if (roleAccount == null) {
            throw new GlobalException(ResponseCode.CONFLICT, "操作失败，角色不存在！");
        }

        /*
         * 角色评分
         * 1、装备评分 = 装备属性评分 + 装备器灵评分 + 装备宝石评分 + 星印评分
         * 2、修炼评分
         * 3、法宝评分 = 普通法宝评分 + 门派法宝评分
         * 4、修为评分 = 等级评分 + 技能评分 + 变化之术评分 + 潜能果评分
         * 5、经脉评分 = 经脉点激活评分 + 镶嵌的晶石评分
         * 6、阵法评分
         */
        AtomicInteger score = new AtomicInteger();

        /*
         * 1、装备评分
         */
        // 1.1 装备属性评分 = 装备评分 × 2
        QueryWrapper<Equipment> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("role_id", roleId);
        queryWrapper.eq("wear_status", WearStatus.YCD.getValue());

        // 查询已经穿戴的装备列表
        List<Equipment> equipmentList = equipmentMapper.selectList(queryWrapper);

        if (CollectionUtils.isNotEmpty(equipmentList) && equipmentList.size() <= 6) {
            for (Equipment equipment : equipmentList) {
                // score += 装备评分 × 2
                score.addAndGet(equipment.getScore() * 2);
            }

            // 得到装备ID列表
            Stream<Equipment> stream = equipmentList.stream();

            List<String> equipmentIds = stream.map(new Function<Equipment, String>() {
                @Override
                public String apply(Equipment equipment) {
                    return equipment.getId();
                }
            }).collect(Collectors.toList());

            // 1.2 装备器灵评分
            QueryWrapper<Qiling> queryWrapper1 = new QueryWrapper<>();

            queryWrapper1.eq("role_id", roleId);
            queryWrapper1.in("equipment_id", equipmentIds);
            queryWrapper1.eq("inlay_status", InlayStatus.YXQ.getValue());

            // 查询已经镶嵌在装备上的器灵列表
            List<Qiling> qilingList = qilingMapper.selectList(queryWrapper1);

            for (Qiling qiling : qilingList) {
                // score += 器灵评分 × 2
                score.addAndGet(qiling.getScore() * 2);
            }

            // 1.3 装备宝石评分
            // 通过装备ID查询装备宝石
            QueryWrapper<EquipmentBaoshi> queryWrapper2 = new QueryWrapper<>();

            queryWrapper2.eq("equipment_id", equipmentIds);

            List<EquipmentBaoshi> list = equipmentBaoshiMapper.selectList(queryWrapper2);

            if (list.size() > 0) {
                // 得到宝石ID
                List<String> baoshiIds = list.stream().map(new Function<EquipmentBaoshi, String>() {
                    @Override
                    public String apply(EquipmentBaoshi equipmentBaoshi) {
                        return equipmentBaoshi.getBaoshiId();
                    }
                }).collect(Collectors.toList());

                // in子句查询镶嵌在装备上的宝石
                QueryWrapper<Baoshi> queryWrapper3 = new QueryWrapper<>();

                queryWrapper3.in("id", baoshiIds);
                queryWrapper3.eq("inlay_status", InlayStatus.YXQ.getValue());

                // 查询已经镶嵌在装备上的宝石列表
                List<Baoshi> baoshiList = baoshiMapper.selectList(queryWrapper3);

                for (Baoshi baoshi : baoshiList) {
                    // score += 宝石等级 × 24
                    score.addAndGet(baoshi.getGrade() * 24);
                }
            }
        }

        // 1.4 星印评分
        QueryWrapper<Xingyin> queryWrapper1 = new QueryWrapper<>();

        queryWrapper1.eq("role_id", roleId);
        queryWrapper1.eq("wear_status", WearStatus.YCD.getValue());

        // 查询角色穿戴的星印
        List<Xingyin> xingyinList = xingyinMapper.selectList(queryWrapper1);

        for (Xingyin xingyin : xingyinList) {
            // score += 星印评分 × 2
            score.addAndGet(xingyin.getScore() * 2);
        }

        score.addAndGet(100);

        /*
         * 2、修炼评分 = 总修炼等级 × 35 = 3360
         */
        QueryWrapper<RoleXiulian> queryWrapper2 = new QueryWrapper<>();

        queryWrapper2.eq("role_id", roleId);

        // 查询角色修炼
        List<RoleXiulian> xiulianList = roleXiulianMapper.selectList(queryWrapper2);

        for (RoleXiulian roleXiulian : xiulianList) {
            // score += 修炼等级 × 35
            score.addAndGet(roleXiulian.getGrade() * 35);
        }

        /*
         * 3、法宝评分
         */
        QueryWrapper<Fabao> queryWrapper3 = new QueryWrapper<>();

        queryWrapper3.eq("role_id", roleId);

        // 查询角色的法宝
        List<Fabao> fabaoList = fabaoMapper.selectList(queryWrapper3);

        for (Fabao fabao : fabaoList) {
            // score += 法宝评分 × 2
            score.addAndGet(fabao.getGrade() * 12);
        }

        // 得到所有法宝ID
        List<String> fabaoIds = fabaoList.stream().map(new Function<Fabao, String>() {
            @Override
            public String apply(Fabao fabao) {
                return fabao.getId();
            }
        }).collect(Collectors.toList());

        // 查询法宝两仪属性
        QueryWrapper<FabaoLiangyiAttribute> queryWrapper4 = new QueryWrapper<>();

        queryWrapper4.in("fabao_id", fabaoIds);

        // 查询角色法宝的所有两仪属性
        List<FabaoLiangyiAttribute> liangyiAttributeList = fabaoLiangyiAttributeMapper.selectList(queryWrapper4);

        for (FabaoLiangyiAttribute liangyiAttribute : liangyiAttributeList) {
            Integer valueId = liangyiAttribute.getValueId();
            FabaoLiangyiAttributeValue fabaoLiangyiAttributeValue = fabaoLiangyiAttributeValueMapper.selectById(valueId);

            Integer valueScore = fabaoLiangyiAttributeValue.getScore();

            // 得到法宝ID
            String fabaoId = liangyiAttribute.getFabaoId();
            // 查询法宝类型信息
            Fabao fabao = fabaoMapper.selectById(fabaoId);
            FabaoCategory fabaoCategory = fabaoCategoryMapper.selectById(fabao.getCategoryId());

            // 门派法宝的两仪属性评分是普通法宝的两倍
            if (FabaoTypes.MPFB.getValue().equals(fabaoCategory.getType())) {
                valueScore *= 2;
            }

            score.addAndGet(valueScore);
        }

        /*
         * 4、修为评分
         */
        // 4.1 等级评分 = 人物等级 × 30
        score.addAndGet(roleAccount.getGrade() * 30);

        // 4.2 技能评分 = 门派技能等级之和 + 帮派技能等级之和
        // 4.2.1 门派技能
        QueryWrapper<SchoolSkill> queryWrapper5 = new QueryWrapper<>();

        queryWrapper5.eq("role_id", roleId);

        // 查询角色的门派技能
        List<SchoolSkill> schoolSkillList = schoolSkillMapper.selectList(queryWrapper5);

        for (SchoolSkill schoolSkill : schoolSkillList) {
            // score += 门派技能等级
            score.addAndGet(schoolSkill.getGrade());
        }

        // 4.2.2 帮派技能
        QueryWrapper<GangSkill> queryWrapper6 = new QueryWrapper<>();

        queryWrapper6.eq("role_id", roleId);
        queryWrapper6.inSql("category_id",
                "select id from gang_skill_category where score > 0");

        // 只查询会增加评分的帮派技能
        List<GangSkill> gangSkillList = gangSkillMapper.selectList(queryWrapper6);

        for (GangSkill gangSkill : gangSkillList) {
            // score += 帮派技能等级
            score.addAndGet(gangSkill.getGrade());
        }

        // 4.3 变化之术评分 = 变化之术等级之和 × 30
        QueryWrapper<RoleChangeSorcery> queryWrapper7 = new QueryWrapper<>();

        queryWrapper7.eq("role_id", roleId);

        // 查询角色变化之术信息
        List<RoleChangeSorcery> changeSorceryList = roleChangeSorceryMapper.selectList(queryWrapper7);

        for (RoleChangeSorcery changeSorcery : changeSorceryList) {
            // score += 变化之术等级 × 30
            score.addAndGet(changeSorcery.getGrade() * 30);
        }

        // 4.4 潜能果评分 = 潜能果个数 × 3 + 四时个数 × 4 + 天象个数 × 10 + 节气个数 × 10
        // 4.4.1 score += 潜能果个数 × 3
        QueryWrapper<PotencyFruit> queryWrapper8 = new QueryWrapper<>();

        queryWrapper8.eq("role_id", roleId);

        Long count = potencyFruitMapper.selectCount(queryWrapper8);

        if (count > 0) {
            score.addAndGet((int) (count * 3));

            // 4.4.2 score += 四时个数 × 4 + 天象个数 × 10 + 节气个数 × 10
            List<GroupResult> groupResults = potencyFruitPatternMapper.selectCountGroupByType(roleId);

            for (GroupResult groupResult : groupResults) {
                Integer weight = groupResult.getType() == 1 ? 4 : 10;

                score.addAndGet(groupResult.getCount() * weight);
            }
        }

        /*
         * 5、经脉评分
         */
        QueryWrapper<JingmaiPoint> queryWrapper9 = new QueryWrapper<>();

        queryWrapper9.eq("role_id", roleId);

        List<JingmaiPoint> jingmaiList = jingmaiPointMapper.selectList(queryWrapper9);

        for (JingmaiPoint jingmaiPoint : jingmaiList) {
            String stoneId = jingmaiPoint.getStoneId();

            if (StringUtils.isNotEmpty(stoneId)) {
                // 晶石评分
                StarStone starStone = starStoneMapper.selectById(stoneId);
                StarStoneCategory starStoneCategory = starStoneCategoryMapper.selectById(starStone.getCategoryId());

                score.addAndGet(starStoneCategory.getScore());
            }

            score.addAndGet(60);
        }

        /*
         * 6、阵法评分 = 最高阵法等级 × 100 = 500
         */
        QueryWrapper<RoleZhenfa> queryWrapper10 = new QueryWrapper<>();

        queryWrapper10.eq("role_id", roleId);

        // 查询角色的所有阵法信息
        List<RoleZhenfa> zhenfaList = roleZhenfaMapper.selectList(queryWrapper10);

        if (CollectionUtils.isNotEmpty(zhenfaList)) {
            // 对阵法按照等级倒序排序，集合第一个元素就是等级最高的阵法
            zhenfaList.sort(new Comparator<RoleZhenfa>() {
                @Override
                public int compare(RoleZhenfa zhenfa1, RoleZhenfa zhenfa2) {
                    return zhenfa2.getGrade() - zhenfa1.getGrade();
                }
            });

            // score += 阵法等级 × 100
            Integer grade = zhenfaList.get(0).getGrade();

            score.addAndGet(grade * 100);
        }

        return score.intValue();
    }

}